C and C++ Design Considerations

Component objects contain data specific to the object and one or more interface implementations. The data is private and inaccessible from outside the object, while the interface implementations are public and you can access them through pointers.

Because interfaces are a binary standard, interface implementation is language independent. However, C++ is the preferred language because it supports many of the object-oriented concepts inherent in OLE. Using a procedural language such as C involves extra work, as summarized below:

    You must explicitly initialize VTBLs either at compile-time or run-time and you should not change them later. Once initialized with function pointers, those pointers should remain unchanged until the application shuts down. VTBLs in C++ are declared as constants to prevent them from being modified inadvertently. However, in C there is no way to ensure that a VTBL will remain unchanged.

To overcome this difference, OLE provides a mechanism that lets C developers declare VTBLs as constants. To do so, place the following statement before the #include statement for the  ole2.h  header file:

#define CONST_VTABLE

 

    Each method requires a pointer to the object that owns the method. In C++, all members are implicitly dereferenced off the this pointer. In C, there must be an additional first parameter passed to each method that is a pointer to the interface in which the method is declared.

    Methods in C++ can have identical names because methods are actually known by a name that is the result of concatenating the method name to the class name. Methods in C must have a unique name to designate the object with which they are associated.

 

For example, the following C++ code sample defines an implementation of IUnknown::QueryInterface2Y54585. The method name is QueryInterface and there are two parameters: a REFIID and a pointer to where to return the requested interface instance.

CUnknown::QueryInterface (REFIID riid, LPVOID * ppvObj);

 

A similar C implementation would require a more complex name and an additional first parameter to indicate the object owning the method:

IUnknown_Doc_QueryInterface (LPUNKNOWN pUnk, REFIID riid,

    LPVOID * ppvObj);

 

The following sections demonstrate how to declare a component object in a few typical ways: using C nested data structures, C++ nested classes, and C++ multiple inheritance. The demonstration object, called CObj, derives from IUnknown1NEM0LU and supports two interfaces that also derive from IUnknown, InterfaceA and InterfaceB. CObj s private data includes a pointer to another component object in the application (m_pCDoc), a count of all the external references to the object (m_ObjRefCount), and pointers to two interfaces implemented by other component objects and used by CObj (m_pOleObj and m_pStg). All object members use the m_ prefix to make it easy to distinguish between member variables and other variables.